package com.heima.article.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.IApArticleConfigService;
import com.heima.article.service.IApArticleContentService;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IApAuthorService;
import com.heima.common.constants.article.ArticleHomeConstants;
import com.heima.common.exception.CustomizeExceptionBuilder;
import com.heima.feign.clients.AdminClient;
import com.heima.feign.clients.WemediaClient;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ApArticleHomeDTO;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleConfig;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.article.pojos.ApAuthor;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ApArticleService extends ServiceImpl<ApArticleMapper, ApArticle> implements IApArticleService {

    @Autowired
    private WemediaClient wemediaClient;
    @Autowired
    private GeneratePageService generatePageService;

    /**
     * 处理文章发布
     * @param newsId
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void publishArticle(Integer newsId) {
        //1.远程调用查询 WmNews 信息并判断状态
        WmNews wmNews = getWmNews(newsId);
        //2.封装 ApArticle 信息
        ApArticle apArticle = createApArticle(wmNews);
        //3.保存或修改 ApArticle 信息
        apArticle = saveOrnUpdateApArticle(apArticle);
        //4.页面静态化
        generatePageService.generateArticlePage(wmNews.getContent(), apArticle);
        //5.封装 ApArticleConfig 和 ApArticleContent 信息
        saveConfigAndContent(apArticle, wmNews);
        //6.更新 WeNews 的状态并补全信息
        updateWmNewsInfo(wmNews, apArticle.getId());
        //TODO: 7.异步回调通知 ElasticSearch 更新索引库
    }

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Value("${file.oss.web-site}")
    private String webSite;
    @Value("${file.minio.readPath}")
    private String readPath;

    /**
     * APP 端-首页加载-查询文章
     * @param apArticleHomeDTO
     * @return
     */
    @Override
    public ResponseResult findArticlesByChannel(ApArticleHomeDTO apArticleHomeDTO) {
        //1.参数校验
            //1.1校验 size
        if(apArticleHomeDTO.getSize() == null){
            apArticleHomeDTO.setSize(10);
        }
            //1.2校验 tag
        if(apArticleHomeDTO.getTag() == null){
            apArticleHomeDTO.setTag(ArticleHomeConstants.RECOMMEND_TAG);
        }
            //1.3校验最大时间
        if(apArticleHomeDTO.getMaxBehotTime() == null){
            apArticleHomeDTO.setMaxBehotTime(new Date());
        }
            //1.4校验最小时间
        if(apArticleHomeDTO.getMinBehotTime() == null){
            apArticleHomeDTO.setMinBehotTime(new Date());
        }
            //1.5校验 loaddir
        if((!ArticleHomeConstants.LOAD_TYPE_NEW.equals(apArticleHomeDTO.getLoaddir()) && !ArticleHomeConstants.LOAD_TYPE_NORMAL.equals(apArticleHomeDTO.getLoaddir())) && !ArticleHomeConstants.LOAD_TYPE_MORE.equals(apArticleHomeDTO.getLoaddir())){
            apArticleHomeDTO.setLoaddir(ArticleHomeConstants.LOAD_TYPE_NORMAL);
        }
        //2.查询文章
        List<ApArticle> apArticles = apArticleMapper.findApArticleByChannel(apArticleHomeDTO);
        for (ApArticle apArticle : apArticles) {
            apArticle.setStaticUrl(readPath + apArticle.getStaticUrl());
        }
        //3.返回响应
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        responseResult.setHost(webSite);
        return responseResult;
    }

    /**
     * 更新 WmNews 的状态并补全信息
     * @param wmNews
     * @param apArticleId
     */
    private void updateWmNewsInfo(WmNews wmNews, Long apArticleId) {
        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        wmNews.setArticleId(apArticleId);
        ResponseResult updateResult = wemediaClient.updateWmNewsById(wmNews);
        if(updateResult.getCode().intValue() != 0){
            log.error("处理文章发布失败，失败原因: {}, WmNews 内容: {}", updateResult.getErrorMessage(), wmNews);
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.REMOTE_SERVER_ERROR, updateResult.getErrorMessage());
        }
    }

    /**
     * 保存 ApArticleConfig 和 ApArticleContent 信息
     * @param apArticle
     * @param wmNews
     */
    private void saveConfigAndContent(ApArticle apArticle, WmNews wmNews) {
        //封装 ApArticleConfig
        ApArticleConfig apArticleConfig = new ApArticleConfig();
        apArticleConfig.setArticleId(apArticle.getId());
        apArticleConfig.setIsComment(true);
        apArticleConfig.setIsForward(true);
        apArticleConfig.setIsDown(false);
        apArticleConfig.setIsDelete(false);
        apArticleConfigService.save(apArticleConfig);
        //封装 ApArticleContent
        ApArticleContent apArticleContent = new ApArticleContent();
        apArticleContent.setArticleId(apArticle.getId());
        apArticleContent.setContent(wmNews.getContent());
        apArticleContentService.save(apArticleContent);
    }

    @Autowired
    private IApArticleConfigService apArticleConfigService;
    @Autowired
    private IApArticleContentService apArticleContentService;

    /**
     * 保存或修改 ApArticle
     * @param apArticle
     * @return
     */
    private ApArticle saveOrnUpdateApArticle(ApArticle apArticle) {
        if(apArticle.getId() == null){
            //保存 - 补全 ApArticle 信息
            apArticle.setLikes(0);
            apArticle.setCollection(0);
            apArticle.setComment(0);
            apArticle.setViews(0);
            //apArticle.setSyncStatus();    ApArticle 同步状态
            //apArticle.setOrigin();    ApArticle 来源
            this.save(apArticle);
        }else {
            //修改 - 删除旧的 ApArticleConfig 和 ApArticleContent 信息
            ApArticle oldArticle = this.getById(apArticle.getId());
            if(oldArticle == null){
                log.error("处理文章发布失败，失败原因: {}, ApArticle id: {}", "修改已发布的 ApArticle 时, 未能查询到旧的 ApArticle, 出现脏数据", apArticle.getId());
                CustomizeExceptionBuilder.builder(AppHttpCodeEnum.DATA_NOT_EXIST, "旧的 ApArticle 不存在，无法修改");
            }
            this.updateById(apArticle);
            apArticleConfigService.remove(Wrappers.<ApArticleConfig>lambdaQuery().eq(ApArticleConfig::getArticleId, apArticle.getId()));
            apArticleContentService.remove(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, apArticle.getId()));
        }
        return apArticle;
    }

    @Autowired
    private AdminClient adminClient;
    @Autowired
    private IApAuthorService apAuthorService;

    /**
     * 根据 WmNews 初步封装 ApArticle
     * @param wmNews
     * @return
     */
    private ApArticle createApArticle(WmNews wmNews) {
        ApArticle apArticle = new ApArticle();
        apArticle.setTitle(wmNews.getTitle());
        apArticle.setChannelId(wmNews.getChannelId());
        ResponseResult<AdChannel> adChannelResult = adminClient.findChannelById(wmNews.getChannelId());
        if(adChannelResult.getCode().intValue() != 0){
            log.error("处理文章发布失败，失败原因: {}", adChannelResult.getErrorMessage());
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.REMOTE_SERVER_ERROR, adChannelResult.getErrorMessage());
        }
        ApAuthor apAuthor = apAuthorService.getOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getWmUserId, wmNews.getUserId()));
        if(apAuthor == null){
            log.error("处理文章发布失败，失败原因: {}, 对应的用户 id: {}", "WmUser 相关的 ApUser 所对应 ApAuthor 不存在", wmNews.getUserId());
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.DATA_NOT_EXIST, "文章作者不存在");
        }
        apArticle.setAuthorId(apAuthor.getId());
        apArticle.setAuthorName(apAuthor.getName());
        AdChannel adChannel = adChannelResult.getData();
        apArticle.setChannelName(adChannel.getName());
        apArticle.setLayout(wmNews.getType());
        apArticle.setFlag((short) 0);
        apArticle.setImages(wmNews.getImages());
        apArticle.setLabels(wmNews.getLabels());    //TODO: WmNews 创建时能够解析多标签
        apArticle.setCreatedTime(wmNews.getCreatedTime());
        apArticle.setPublishTime(wmNews.getPublishTime());
        //apArticle.setSyncStatus(wmNews.); ????
        return apArticle;
    }

    /**
     * 根据 WmNews id 获取 WmNews 详细信息
     * @param newsId
     * @return
     */
    private WmNews getWmNews(Integer newsId) {
        if(newsId == null){
            log.error("处理文章发布失败，失败原因: {}", "WmNews id 为空");
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.PARAM_INVALID, "WmNews id 不能为空");
        }
        ResponseResult<WmNews> wmNewsResult = wemediaClient.queryWmNewsById(newsId);
        if(wmNewsResult.getCode().intValue() != 0){
            log.error("处理文章发布失败，失败原因: {}", wmNewsResult.getErrorMessage());
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.REMOTE_SERVER_ERROR, wmNewsResult.getErrorMessage());
        }
        return wmNewsResult.getData();
    }
}
